﻿#include "pipeGraph.h"

PipeGraph::PipeGraph()
{
    // 初始化 图构建
    vertexNum = 26;
    vertexList.push_back(stVertex(0,  true,  true));
    vertexList.push_back(stVertex(1,  true,  false));
    vertexList.push_back(stVertex(2,  true,  false));
    vertexList.push_back(stVertex(3,  true,  true));
    vertexList.push_back(stVertex(4,  true,  false));
    vertexList.push_back(stVertex(5,  true,  false));
    vertexList.push_back(stVertex(6,  true,  false));
    vertexList.push_back(stVertex(7,  false, false));
    vertexList.push_back(stVertex(8,  false, false));
    vertexList.push_back(stVertex(9,  false, false));
    vertexList.push_back(stVertex(10, false, false));
    vertexList.push_back(stVertex(11, false, false));
    vertexList.push_back(stVertex(12, false, false));
    vertexList.push_back(stVertex(13, false, false));
    vertexList.push_back(stVertex(14, false, false));
    vertexList.push_back(stVertex(15, false, false));
    vertexList.push_back(stVertex(16, false, false));
    vertexList.push_back(stVertex(17, false, false));
    vertexList.push_back(stVertex(18, false, false));
    vertexList.push_back(stVertex(19, false, false));
    vertexList.push_back(stVertex(20, false, false));
    vertexList.push_back(stVertex(21, false, false));
    vertexList.push_back(stVertex(22, false, true));
    vertexList.push_back(stVertex(23, false, true));
    vertexList.push_back(stVertex(24, false, true));
    vertexList.push_back(stVertex(25, false, true));

    for(int i = 0; i < 26; i ++){
        edgeList.push_back(QVector<stEdge>());
        for(int j = 0; j < 26; j ++){
            edgeList[i].push_back(stEdge());
        }
    }

    // 边的状态
    setEdgeConnectState(1, 12, true, 21.7);
    setEdgeConnectState(2, 12, true, 21.7);
    setEdgeConnectState(0, 12, true, 21.5);
    setEdgeConnectState(0, 3, true, 55.6);

    // 注射器3下发
    setEdgeConnectState(3, 13, true, 25);
    setEdgeConnectState(13, 19, true, 83.4);
    setEdgeConnectState(19, 18, true, 14);
    setEdgeConnectState(17, 18, true, 10);

    setEdgeConnectState(17, 15, true, 51.2);

    // 注射器4下发
    setEdgeConnectState(14, 15, true, 20);
    setEdgeConnectState(14, 4, true, 19.2);

    // 注射器5下发
    setEdgeConnectState(5, 15, true, 8.5);

    // 注射器6下发
    setEdgeConnectState(6, 16, true, 9);
    setEdgeConnectState(7, 16, true, 10);

    // 假装没有的那一段awa
    setEdgeConnectState(7, 17, true, 2);

    // 上面的那一长段（距离没确定）
    setEdgeConnectState(7, 20, true, 80);
    setEdgeConnectState(20, 21, true, 80);
    setEdgeConnectState(21, 10, true, 80);

    // 阀门10
    setEdgeConnectState(8, 9, true, 30);
    setEdgeConnectState(22, 8, true, 23);

    // 阀门11
    setEdgeConnectState(23, 9, true, 8);

    // 阀门12
    setEdgeConnectState(9, 10, true, 43);

    // 阀门14
    setEdgeConnectState(10, 11, true, 6.7);

    // 阀门13和15
    setEdgeConnectState(24, 11, true, 18);
    setEdgeConnectState(25, 11, true, 18);

    // 阀门
    valveList.push_back(stValve(1, 1, 12));
    valveList.push_back(stValve(2, 2, 12));
    valveList.push_back(stValve(3, 0, 12));
    valveList.push_back(stValve(4, 0, 3));
    valveList.push_back(stValve(5, 14, 15));
    valveList.push_back(stValve(6, 5, 15));
    valveList.push_back(stValve(7, 7, 16));
    valveList.push_back(stValve(8, 17, 18));
    valveList.push_back(stValve(9, 15, 17));
    valveList.push_back(stValve(10, 8, 22));
    valveList.push_back(stValve(11, 9, 23));
    valveList.push_back(stValve(12, 9, 10));
    valveList.push_back(stValve(13, 11, 25));
    valveList.push_back(stValve(14, 10, 11));
    valveList.push_back(stValve(15, 11, 24));

    for(int i = 0; i < valveList.size(); i ++){
        setEdgeHasValve(valveList[i].v1, valveList[i].v2, true);
    }
//    updateLiquidPath();

    // 初始化注射器的速度
    syringeSpeed = {0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5};     // 初始化注射器速度为0.5ml/s

}

bool PipeGraph::isVertexConnect(int v1, int v2){

    int tmpv1 = v1, tmpv2 = v2; v1 = std::min(tmpv1, tmpv2); v2 = std::max(tmpv1, tmpv2);

    return EDGE(v1, v2).connect;
}


void PipeGraph::setEdgeHasValve(int v1, int v2, bool state){
    EDGE(v1, v2).hasValve = state;
}
void PipeGraph::setEdgeValveState(int v1, int v2, bool state){

    int tmpv1 = v1, tmpv2 = v2; v1 = std::min(tmpv1, tmpv2); v2 = std::max(tmpv1, tmpv2);
    EDGE(v1, v2).valveState = state;
}
void PipeGraph::setEdgeConnectState(int v1, int v2, bool state, double length){

    length /= goodLength;        // 就是有1个ms的speed大于一段length的情况，救不了了，3.5m/s是什么速度哇……

    EDGE(v1, v2).connect = state;
    EDGE(v1, v2).length = length;
    EDGE(v1, v2).goodLists.clear();
    for(int i = 0; i < length; i ++){
        EDGE(v1, v2).goodLists.push_back(stGoods());
    }
//    qDebug() << "边" << v1 << v2 << "存入" << length << "个Goods";

}
bool PipeGraph::getEdgeState(int v1, int v2){
    int tmpv1 = v1, tmpv2 = v2; v1 = std::min(tmpv1, tmpv2); v2 = std::max(tmpv1, tmpv2);
    return EDGE(v1, v2).connect && ( (!EDGE(v1, v2).hasValve) || EDGE(v1, v2).valveState);
}

void PipeGraph::updateValveState(QVector<bool> valveState){
    if(valveState.size() != valveList.size()){
        qDebug() << "ERROR: [Class]PipeGraph [Func]updateValueState - Different Vector Size";
    }
    for(int i = 0; i < valveState.size(); i ++){
        valveList[i].state = valveState[i];
        setEdgeValveState(valveList[i].v1, valveList[i].v2, valveState[i]);
    }
//    updateLiquidPath();
}

void PipeGraph::setVertexEmitting(int sv, bool state){
    vertexList[sv].emitting = state;
//    updateLiquidPath();
}

void PipeGraph::updateLiquidPath(){



    liquidPath.clear();
    foreach(stVertex vertex, vertexList){
        if(!(vertex.isStart && vertex.emitting)) continue;
        QVector<bool> flag(vertexNum, false);
        liquidPath.push_back(recursivePath(vertex.idx, flag));
    }

    foreach(TreeNode* root, liquidPath){
        root->updateForkNum();
    }
    updateEdgeSpeed();      // 更新速度
    for(int i = 0; i < vertexNum; ++ i){          // 打印管道速度
        for(int j = i; j < vertexNum; ++ j){
            if(edgeList[i][j].speed != 0){
//                qDebug() << "边" << i <<j << "的速度为" << edgeList[i][j].speed;
            }
        }
    }



    // 更新

    moveAllGoods = false;
    int execTimes = 0;
    while(!moveAllGoods){
//        qDebug() << "执行updateGoods的第" << execTimes << "次循环 ===================================";
        updateGoods();
        execTimes ++;
        if(execTimes > 100){
            qDebug() << "[ERROR] UpdateGoods可能存在问题造成死循环，已自动中断执行";
            break;
        }
    }
    supplyGoods();

    getLiquidState();
}

void PipeGraph::supplyGoods(){

//    qDebug() << "当前边的状态";

//    for(int v1 = 0; v1 < vertexNum; v1 ++){
//        for(int v2 = v1+1; v2 < vertexNum; v2 ++){
//            if(!EDGE(v1, v2).connect){
//                continue;
//            }
//            qDebug() << "边" << v1 << v2 << "长度" << EDGE(v1, v2).goodLists.size();

//        }
//    }


    for(int v1 = 0; v1 < vertexNum; v1 ++){
        for(int v2 = v1+1; v2 < vertexNum; v2 ++){
            if(!EDGE(v1, v2).connect || EDGE(v1, v2).speed == 0){
                continue;
            }
            while(EDGE(v1, v2).goodLists.length() < EDGE(v1, v2).length){
                // 从后补位一个（这准吗）
                if(EDGE(v1, v2).goodLists.size()==0){
//                    qDebug() << "出现问题：边" << v1 << v2 << "中内容为0";
                    EDGE(v1, v2).goodLists.push_back(stGoods(9));
                }else{
                    EDGE(v1, v2).goodLists.push_back(EDGE(v1, v2).goodLists.back());
                }
            }
        }
    }
}

void PipeGraph::updateGoods(){
//    qDebug() << "updateGoods开始计算";

    moveAllGoods = true;

    QElapsedTimer timer;
    timer.start();

    int moveTimes = 0;

    for(int v1 = 0; v1 < vertexNum; v1 ++){
        for(int v2 = v1+1; v2 < vertexNum; v2 ++){

            if(!EDGE(v1, v2).connect || EDGE(v1, v2).speed == 0){
                continue;
            }
//            qDebug() << "处理边" << v1 << v2 << "当前边的速度" << EDGE(v1, v2).speed;

            // Case1 该点是发射源头 ===============================   // 向该点push
            if(vertexList[v1].emitting || vertexList[v2].emitting){
                while(EDGE(v1, v2).enterCount > 0){
                    EDGE(v1, v2).enterCount --;
                    if(EDGE(v1, v2).speed > 0){
                        edgeList[v1][v2].goodLists.push_front(stGoods(v1));
                    }else{
                        edgeList[v1][v2].goodLists.push_back(stGoods(v2));
                    }
                    moveTimes ++;
                }
            }else{      // Case2 该点是一条中间的边 =============================
                if(EDGE(v1, v2).speed > 0){     // 从数字小的那边往里加
                    // 遍历数字小的那个顶点所连的所有边，如果该边有向该点流动的趋势，则从改边取“流速”个goods加到这边
                    for(int v = 0; v < vertexNum; v ++){
                        if(v < v1){
                            if(EDGE(v, v1).speed > 0){
//                                qDebug() << "\t前一条输液边为" << v << v1 << "Goods数量" << EDGE(v, v1).goodLists.size();
                                while(EDGE(v1, v2).enterCount > 0){
                                    if(EDGE(v, v1).goodLists.size() > 0){
                                        EDGE(v1, v2).goodLists.push_front(stGoods(EDGE(v, v1).goodLists.back()));
                                        EDGE(v, v1).goodLists.pop_back();
                                        moveTimes ++;
                                        EDGE(v1, v2).enterCount --;
                                    }else{
//                                        qDebug() << "\t异常:" << v << v1 << "管道里面没有goods";
                                        break;
                                    }
                                }
//                                qDebug() << "边" << v1 << v2 << "剩余未进入的goods数量" << EDGE(v1, v2).enterCount;
//                                qDebug() << "边" << v1 << v2 << "当前goods数量" << EDGE(v1, v2).goodLists.size();
                                if(EDGE(v1, v2).enterCount > 0){
                                    moveAllGoods = false;
                                }
                            }
                        }else if(v == v1){
                            continue;
                        }else{   // v1 < v
                            if(EDGE(v, v1).speed < 0){

//                                qDebug() << "\t前一条输液边为" << v1 << v << "Goods数量" << EDGE(v, v1).goodLists.size();
                                while(EDGE(v1, v2).enterCount > 0){
                                    if(EDGE(v, v1).goodLists.size() > 0){
                                        EDGE(v1, v2).goodLists.push_front(stGoods(EDGE(v, v1).goodLists.front()));
                                        EDGE(v, v1).goodLists.pop_front();
                                        moveTimes ++;
                                        EDGE(v1, v2).enterCount --;
                                    }else{
//                                        qDebug() << "\t异常:" << v1 << v <<"管道里面没有goods";
                                        break;
                                    }
                                }
//                                qDebug() << "边" << v1 << v2 << "剩余未进入的goods数量" << EDGE(v1, v2).enterCount;
//                                qDebug() << "边" << v1 << v2 << "当前goods数量" << EDGE(v1, v2).goodLists.size();
                                if(EDGE(v1, v2).enterCount > 0){
                                    moveAllGoods = false;
                                }
                            }
                        }
                    }
                }else{      // 从数字大的那边往里加

                    // 遍历数字大的那个顶点所连的所有边，如果该边有向该点流动的趋势
                    for(int v = 0; v < vertexNum; v ++){
                        if(v < v2){
                            if(edgeList[v][v2].speed > 0){
//                                qDebug() << "\t前一条输液边为" << v << v2 << "Goods数量" << EDGE(v, v2).goodLists.size();
                                while(EDGE(v1, v2).enterCount > 0){
                                    if(EDGE(v, v2).goodLists.size() > 0){
                                        EDGE(v1, v2).goodLists.push_back(stGoods(edgeList[v][v2].goodLists.back()));
                                        EDGE(v, v2).goodLists.pop_back();
                                        moveTimes ++;
                                        EDGE(v1, v2).enterCount --;
                                    }else{
//                                        qDebug() << "\t异常:" << v << v2 <<"管道里面没有goods";
                                        break;
                                    }
                                }
//                                qDebug() << "边" << v1 << v2 << "剩余未进入的goods数量" << EDGE(v1, v2).enterCount;
//                                qDebug() << "边" << v1 << v2 << "当前goods数量" << EDGE(v1, v2).goodLists.size();
                                if(EDGE(v1, v2).enterCount > 0){
                                    moveAllGoods = false;
                                }
                            }
                        }else if(v == v2){
                            continue;
                        }else{      // v2 < v
                            if(edgeList[v2][v].speed < 0){

//                                qDebug() << "\t前一条输液边为" << v2 << v << "Goods数量" << EDGE(v, v2).goodLists.size();
                                while(EDGE(v1, v2).enterCount > 0){
                                    if(EDGE(v, v2).goodLists.size() > 0){
                                        EDGE(v1, v2).goodLists.push_back(stGoods(edgeList[v2][v].goodLists.front()));
                                        EDGE(v, v2).goodLists.pop_front();
                                        moveTimes ++;
                                        EDGE(v1, v2).enterCount --;
                                    }else{
//                                        qDebug() << "\t异常:" << v2 << v <<"管道里面没有goods";
                                        break;
                                    }
                                }
//                                qDebug() << "边" << v1 << v2 << "剩余未进入的goods数量" << EDGE(v1, v2).enterCount;
//                                qDebug() << "边" << v1 << v2 << "当前goods数量" << EDGE(v1, v2).goodLists.size();
                                if(EDGE(v1, v2).enterCount > 0){
                                    moveAllGoods = false;
                                }
                            }
                        }
                    }
                }
            }

            // Case 3 该点最后走没了
            if(vertexList[v1].isEnd || vertexList[v2].isEnd){
                while (EDGE(v1, v2).outCount > 0) {
                    if(EDGE(v1, v2).goodLists.size() > 0){

                        if(EDGE(v1, v2).speed > 0){
                            EDGE(v1, v2).goodLists.pop_back();
                        }else{
                            EDGE(v2, v1).goodLists.pop_front();
                        }
                        EDGE(v1, v2).outCount --;
                    }else{
                        break;
                    }
                }

            }
        }
    }



//    qDebug() << "updateGoods的时间:" << timer.elapsed() << "ms" << "  运动次数:" << moveTimes;
}

void PipeGraph::clearEdgeSpeed(){
    for(int i = 0; i < edgeList.size(); ++ i){
        for(int j = i; j < edgeList[i].size(); ++ j){
            edgeList[i][j].speed = 0;
        }
    }
}

void PipeGraph::clearPipe(){


    for(int v1 = 0; v1 < vertexNum; v1 ++){
        for(int v2 = v1+1; v2 < vertexNum; v2 ++){

            if(!EDGE(v1, v2).connect){
                continue;
            }
            for(int i = 0; i < EDGE(v1, v2).goodLists.size(); ++ i){
                EDGE(v1, v2).goodLists[i].idx = 9;
            }
        }
    }
}

void PipeGraph::updateEdgeSpeed(){      // 根据liquidPath更新每个传送带的速度
//    qDebug() << "开始更新Edge的速度";
    clearEdgeSpeed();


    if(!elapsedTimer){
        elapsedTimer = new QElapsedTimer();
        elapsedTimer->start();
    }
    // 更新了的速度
    int gapTime = elapsedTimer->elapsed() - lastUpdateLiquidTime;
    lastUpdateLiquidTime = elapsedTimer->elapsed();
//    qDebug() << "updateEdgeSpeed调用时间间隔" << gapTime;


    foreach(TreeNode* root, liquidPath){
//        qDebug() << "遍历某一个根节点";
//        qDebug() << root->print();
//        if(root->idx < 0){
//            qDebug() << "出现错误: liquidPath里面有根节点的路径<0";
//        }
        if(syringeSpeed.size() > root->idx && root->idx >= 0){
//            qDebug() << "注射器" << root->idx << "速度" << syringeSpeed[root->idx];
            double emitSpeed = 4*syringeSpeed[root->idx] / (diameter*diameter*3.1415926);      // 管道的速度，单位mm/ms
//            qDebug() << "管道速度" << emitSpeed << "(mm/ms)";
            updateEdgeSpeed_recursive(root, emitSpeed*gapTime/goodLength);       // 根据注射器的速度更新速度
        }else{
            updateEdgeSpeed_recursive(root, 1000);       // 默认的速度
        }
//        qDebug() << root->print();
    }
//    qDebug() << "更新完成";
}

void PipeGraph::updateEdgeSpeed_recursive(TreeNode* startVertex, double speed){
    foreach(TreeNode* son, startVertex->son){
        if(son->idx == -1){
            continue;
        }
        int v1 = std::min(startVertex->idx, son->idx); int v2 = std::max(startVertex->idx, son->idx);
        int sign = startVertex->idx < son->idx ? 1 : -1;    // 正负号
        EDGE(v1, v2).speed += speed / son->forkNum * sign;
        EDGE(v1, v2).enterCount = std::abs(EDGE(v1, v2).speed);
        EDGE(v1, v2).outCount = std::abs(EDGE(v1, v2).speed);
        updateEdgeSpeed_recursive(son, speed);
    }
}

TreeNode* PipeGraph::recursivePath(int v, QVector<bool> &flag){         // 液路搜索（递归）

    flag[v] = true;
    TreeNode* resNode = new TreeNode(-1);

    // 抵达终点
    if(vertexList[v].isEnd && !vertexList[v].emitting){
        resNode->idx = v;
        return resNode;
    }
//    // 到达起点
//    if(vertexList[v].isStart){
//        return resNode;
//    }
    // 遍历周围的每个点
    for(int i = 0; i < vertexNum; i ++){
        if(flag[i]) continue;
        if(getEdgeState(v, i)){
            TreeNode* node = recursivePath(i, flag);
            if(node->idx != -1){
                resNode->idx = v;
                resNode->son.push_back(node);
            }
        }
    }
    return resNode;

}

QVector<TreeNode*> PipeGraph::getLiquidPath(){
    return liquidPath;
}


/*
 * QVariantList{
 *      QVariantMap{
 *          v1: 1
 *          v2: 2
 *          segment: [0.1, 1, 0.3, 4, .....]
 *      }
 *      QVariantMap{
 *          v1: 1
 *          v2: 2
 *          segment: [0.1, 1, 0.3, 4, .....]
 *      }
 *  }
 *
 */

void PipeGraph::changeSyringeSpeed(int idx, double speed){

//    qDebug() << "PipeGraph-ChangeSyringSpeed" << idx << "为" << speed;

    if(speed < 0){
        qDebug() << "changeSyringeSpeed-Failed-Speed<0" << speed;
        return;
    }

    if(syringeSpeed.size() <= idx){
        qDebug() << "changeSyringeSpeed-Failed-indexOutOfRange" << idx;
        return;
    }
    syringeSpeed[idx] = speed;
}

QVariantList PipeGraph::getLiquidState(){

    QVariantList res;


    // 遍历所有edge作为返回结果
    for(int v1 = 0; v1 < vertexNum; ++ v1){
        for(int v2 = v1+1; v2 < vertexNum; v2 ++){
            if(!EDGE(v1, v2).connect)  continue;

            stEdge& edge = EDGE(v1, v2);

            if(edge.goodLists.size() <= 0){
//                qDebug() << "未知错误：" << v1 << v2 << "里面的Goods数量为0";
                continue;
            }

//            // 先把当前edge的结果打印一下
//            QString printLine = "";
//            for(int i = 0; i < edge.goodLists.size(); i += std::max(edge.goodLists.size() / 50, 1)){
//                printLine += QString::number(edge.goodLists[i].idx);
//            }

//            qDebug() << "打印边" << v1 << v2 << "里面Goods的内容:" << printLine;

            QVariantMap line;
            line["V1"] = v1;  line["V2"] = v2;
            QVariantList seg;
            int last_color = edge.goodLists[0].idx;
            int last_idx = 0;
            // 遍历边里面的Goods
            for(int i = 1; i < edge.goodLists.size(); i ++){
                if(last_color != edge.goodLists[i].idx || i==edge.goodLists.size()-1){      // 变换颜色或者到达good的结尾时，输出到res中
                    seg.push_back(double(i-last_idx+1)/edge.goodLists.size());
                    seg.push_back(last_color);
                    last_idx = i;
                    last_color = edge.goodLists[i].idx;
                }
            }
            line["Segment"] = seg;
            res.push_back(line);
        }
    }
//    qDebug() << res;
    return res;
}



